package util.bio.annotation;
import java.io.*;
import java.util.Arrays;

import util.bio.parsers.gff.*;

/**
 * ExonIntron info. 
 */
public class ExonIntron implements Comparable, Serializable {
	//fields
	private int start;
	private int end;
	private String name;
	private String parent;
	
	//constructors
	public ExonIntron (int start, int end){
		this.start = start;
		this.end = end;
	}
	
	public ExonIntron (int start, int end, String name){
		this.start = start;
		this.end = end;
		this.name = name;
	}
	public ExonIntron (Gff3Feature f){
		start = f.getStart();
		end = f.getEnd();
		name = f.getId();
		parent = f.getParent();
	}
	
	//primary methods
	
	/**Assumes interbase coordinates.*/
	public String getSequence(String chromSeq){
		return new String( chromSeq.substring(start, end));
	}
	
	/**Assumes interbase coordinates.*/
	public boolean contains(int position){
		if (position< start || position >= end) return false;
		return true;
	}
	
	
	public String toString(){
		return "ExonIntron: "+start+"-"+end;
	}
	public int compareTo(Object other){
		ExonIntron otherExon = (ExonIntron)other;
		//sort by start position
		if (start<otherExon.start) return -1;
		if (start>otherExon.start) return 1;
		// if same start, sort by length, smaller to larger
		int len = end-start;
		int otherLen = otherExon.end-otherExon.start;
		if (len<otherLen) return -1;
		if (len>otherLen) return 1;
		return 0;
	}
	
	/**Assumes interbase coordinates.*/
	public static ExonIntron[] mergeExonIntrons(ExonIntron[] one, ExonIntron[] two){
		//find min and max
		int[] minMaxOne = minMax(one);
		int[] minMaxTwo = minMax(two);
		int min = minMaxOne[0];
		int max = minMaxOne[1];
		if (minMaxTwo[0]< min) min = minMaxTwo[0];
		if (minMaxTwo[1]> max) max = minMaxTwo[1];
		//load boolean array
		int length = max-min+1;
		boolean[] fetchFalse = new boolean[length];
		Arrays.fill(fetchFalse, true);
		for (int i=0; i< one.length; i++){
			int start = one[i].start -min;
			int stop = one[i].end-min;
			for (int j=start; j< stop; j++) fetchFalse[j] = false;
		}
		for (int i=0; i< two.length; i++){
			int start = two[i].start -min;
			int stop = two[i].end-min;
			for (int j=start; j< stop; j++) fetchFalse[j] = false;
		}
		//retrieve blocks, ends included
		int[][] blocks = ExportIntergenicRegions.fetchFalseBlocks(fetchFalse, 0, 0);
		//convert to interbase coordinate exon introls
		ExonIntron[] ei = new ExonIntron[blocks.length];
		int minPlusOne = min +1;
		for (int i=0; i< ei.length; i++){
			ei[i] = new ExonIntron(blocks[i][0]+min, blocks[i][1]+minPlusOne);
		}
		return ei;
	}
	
	public static int[] minMax(ExonIntron[] ei){
		int min = ei[0].getStart();
		int max = ei[0].getEnd();
		for (int i=1; i< ei.length; i++){
			if (ei[i].start < min) min = ei[i].start;
			if (ei[i].end > max) max = ei[i].end;
		}
		return new int[]{min,max};
	}
	
	//getters
	public String getName() {
		return name;
	}
	public int getEnd() {
		return end;
	}
	public int getStart() {
		return start;
	}
	public String getParent() {
		return parent;
	}

	public void setEnd(int end) {
		this.end = end;
	}

	public void setStart(int start) {
		this.start = start;
	}
}
